package exp.parser;

import error.processing.MyErrorProcessing;
import execution.Executable;
import grammar.parser.FuncDef;
import grammar.parser.FuncFParams;
import semantic.parser.FuncSymbol;
import word.parser.WordElement;

import java.util.ArrayList;
import java.util.List;

public class FuncExp extends UnaryExp implements Executable {
    private final String funcIdent;
    private final List<Exp> paramList = new ArrayList<>();
    private boolean isVoid = false;

    public FuncExp(String funcIdent) {
        super(false, false);
        this.funcIdent = funcIdent;
    }

    public static FuncExp parseFuncExp() {
        assert getAnalyzingWord().getType() == WordElement.WordType.IDENFR;
        String funcIdent = getAnalyzingWord().getWord();
        FuncExp funcExp = new FuncExp(funcIdent);
        int funcPosition = getNowPosition();
        FuncSymbol funcSymbol = getSemanticParser().getFunc(funcIdent);
        FuncDef funcDef = null;
        if (funcSymbol != null) {
            funcDef = funcSymbol.getFuncDef();
            funcExp.isVoid = funcDef.isVoid();
        } else {
            MyErrorProcessing.buildErrorProcessing(MyErrorProcessing.ErrorType.c,
                    getWord(funcPosition));
        }
        analyzeNextWord();
        assert getAnalyzingWord().getType() == WordElement.WordType.LPARENT;
        analyzeNextWord();
        List<FuncFParams.FuncFParam> formatParamList = new ArrayList<>();
        if (Exp.isExpPrefix(getAnalyzingWord())) {
            do {
                Exp exp = Exp.buildExp();
                funcExp.paramList.add(exp);
                formatParamList.add(exp.checkDimension());
                if (getAnalyzingWord().getType() != WordElement.WordType.COMMA) {
                    break;
                } else {
                    analyzeNextWord();
                }
            } while (true);
        }

        if (getAnalyzingWord().getType() != WordElement.WordType.RPARENT) {
            MyErrorProcessing.buildErrorProcessing(MyErrorProcessing.ErrorType.j, getAnalyzingWord(-1));
        } else {
            analyzeNextWord();
        }


        if (funcDef != null) {
            funcDef.paramsCheck(formatParamList, funcPosition);
        }

        return funcExp;
    }


    @Override
    public LVal toLVal() {
        return null;
    }

    @Override
    public void execute() {

        FuncDef funcDef = getSemanticParser().getFunc(funcIdent).
                getFuncDef();
        addScope();

        //参数压栈
        List<FuncFParams.FuncFParam> funcFParamsList = funcDef.getParams().getParams();
        List<List<List<Integer>>> valueList = new ArrayList<>();
        for (Exp exp : this.paramList) {
            List<List<Integer>> value;
            LVal lVal = exp.toLVal();
            if (lVal != null) {
                value = lVal.getValueAsParam();
            } else {
                value = new ArrayList<>();
                value.add(new ArrayList<>());
                value.get(0).add(exp.getValue());
            }
            valueList.add(value);
        }
        for (int i = 0; i < funcFParamsList.size(); ++i) {
            FuncFParams.FuncFParam param = funcFParamsList.get(i);
            List<Integer> listOfDimension = new ArrayList<>();
            listOfDimension.add(param.getLen());
            while (listOfDimension.size() < 2) {
                listOfDimension.add(0, 0);
            }
            getSemanticParser().declVariable(param.getParamName(),
                    getScope(), param.getDimension(), listOfDimension, valueList.get(i));
        }

        //执行函数
        funcDef.execute();


        outScope();
    }

    @Override
    public Integer compute() {
        this.execute();
        Integer reVal = getSemanticParser().getReVal();
        getSemanticParser().setReVal(null);
        return reVal;
    }


    @Override
    public FuncFParams.FuncFParam checkDimension() {
        if (isVoid) {
            return new FuncFParams.FuncFParam(-1, 0, null);
        }
        return new FuncFParams.FuncFParam();
    }
}
